Custom Web Dashboard - #4707
Conversation
Add a new setting in UI Options that lets users replace the QZ home screen with any web dashboard served by the existing local webserver. The QtWebView overlay sits below the top toolbar (keeping start/stop controls always visible) and follows the same pattern already used by the Workout Editor, so it works on iOS, Android and desktop without extra dependencies. Built-in 'bike-pro' dashboard: Apple-style dark design with live power/cadence/speed tiles, a 7-zone power bar that reacts to FTP ratio, a 60-second rolling Chart.js graph, and heart rate / distance / kcal at the bottom. All data comes through the existing WebSocket feed. User dashboards: place files in <appdata>/dashboards/<name>/index.html and they appear automatically in the picker. Community dashboards can be distributed as a simple zip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The guide (docs/custom-dashboard-guide.md) covers file layout, qml.qrc
registration, shared asset paths, the WebSocket API with the correct
{msg:"workout", content:{...}} envelope, full metric field reference for
all device types, control commands, power zone table, minimal example,
and a distribution checklist.
Also fixes the WS message parser in bike-pro/app.js: data lives in
msg.content, not at the message root level.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@Qhilm do you like the idea? |
Automatic update of translatable strings extracted from source code. Updated 30 language files in src/translations/ - Updated by GitHub Actions (Testing Mode) - Triggered by: pull_request - Date: 2026-06-09 08:19:11 UTC
Apple-style dark dashboard for treadmill workouts, inspired by the QZ
Fitness home screen. Highlights:
- Speed hero (1fr): large current speed with colour coding relative to
target (blue = under, green = on target, orange = over), Avg + Max
(session-tracked client-side)
- Target speed bar: fill shows current vs target with an orange marker
at the target value — only visible when a training program is active
- Training program header (collapses to 0-height when no workout is
loaded): workout name, step badge, target speed/incline chips, overall
session progress bar, and row countdown timer
- 4 metric tiles: Pace (min/km), Incline (%), Cadence (spm), Heart Rate
with intensity colour coding (blue/green/orange/red)
- Bottom row: Distance, Watts, Calories
Connects to the same QZ WebSocket feed as the other dashboards
({msg:"workout", content:{...}}), auto-reconnects on disconnect.
Grid layout uses explicit grid-row assignments so the program header
collapsing to height:0 does not disrupt the 1fr speed-hero row.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Complete rewrite of all three files to replace the flat/bland layout with a neon cyberpunk sports HUD: - Dark background (#07070f) with subtle scanline overlay - 96px neon-green speed number with animated glow (shifts orange/teal vs target) - Canvas sparkline with bezier waveform, gradient fill, glowing dot tip, and dashed orange target-speed line - Radial ambient glow behind speed that reacts to over/under target state - 4 metric tiles with individual coloured top accent bars + glow shadows (teal=pace, orange=incline, purple=cadence, red=HR) - Pulsing heart icon animation; HR value colour-codes by zone - Program header with teal glow title, blue pill STEP badge, progress bar with animated gradient fill and glowing leading dot - Fixed status bar (LIVE dot / elapsed / connection) above grid via padding-top Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full restructure to mirror the actual QZ Fitness app layout: - Timeline strip at top with animated runner indicator and progress bar - Interval info row: workout name + "Interval N" badge + detail line (target speed / grade / distance) - Speed section: large number LEFT + live bezier waveform canvas RIGHT (speed shifts teal=under / white=on / orange=over target) - 2x2 metric grid: Cadence | AVG Watt / Heart Rate | Total KCal (HR value colour-codes by zone, pulsing heart icon) - Odometer row with distance - Status bar: device name / total elapsed / connection state Dark navy (#13161e) surface-card aesthetic matching the app screenshot. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This reverts commit 7f976f4.
Re-add the IndicatorOnlySwitch + description label + ComboBox (populated
via rootItem.availableDashboards()) + OK button that were lost from the
General UI Options accordion. The two backing properties
(ui_custom_dashboard_enabled, ui_custom_dashboard_name) were already
present in the Settings {} block — only the visible controls were missing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The controls were erroneously inserted inside the Zwift Options accordion instead of General UI Options. Moved to the correct ColumnLayout with proper brace nesting (missing closing } for ColumnLayout also fixed). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
I mean, it's hard to tell before testing it, but in theory this is super flexible, meaning someone can move away from the built-in tiles and define whatever one wants. Is my understanding correct? If that's the case, then yes, it's pretty cool. The tiles are quite inflexible and on my iPhone 12 Mini, the screen real estate is not well utilized, there's a lot of white space. Hence being able to design my own dashboard would be indeed pretty cool =) |
yeah i know :D
exactly! I also added the guidelines for any LLM to create your own dashboard with a simple prompt
yes indeed :) i make this in order that users can also share the dashboard created so we can have a sort of repository with images :) |
|
Then I think it's a very nice idea. Focus should be on elegant dynamic resizing so dashboards work on different screen sizes. The rounded corners and the notches / Dynamic Islands / etc. of smartphones would need some form of consideration maybe, not sure how complex this is. |
|
it's something that the user should plan, i mean, from the qz side would be just a web view that talks with the back end. So all the UI customization is in the hand of the users. Let's see how it goes! |
The Loader topMargin was set to topBarHeight (120px), leaving the Start/Stop/Lap toolbar row exposed above the WebView. The app's global navigation ToolBar (hamburger/left-sidebar access) is in main.qml's header: property and sits outside the Page coordinate space, so setting topMargin: 0 gives the dashboard full coverage of the page content while the navigation bar remains untouched. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
QtWebView does not automatically reflow the viewport on rotation. Subscribe to Screen.onPrimaryOrientationChanged and reload by clearing and restoring the URL, which forces a fresh layout pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
I meant, let's say I'm building a dashboard. How can I say "keep 2mm or X pixels distance from the notch for this element but that element is decorative, it can can go 'under' the notch". Is that even technically possible? Not a deal breaker, but would be nice. |
|
consider that qz is running under the dynamic island so you don't need to care about this :) |
- main.qml: expose sideBarVisible property, set true/false on drawer onOpened/onClosed so Home.qml can hide the WebView - Home.qml: bind Loader visible to !window.sideBarVisible so the native WebView doesn't occlude the drawer (QtWebView renders as a native view outside QML z-ordering) - homeform.cpp: exclude internal templates (chartjs, googlemaps, maps2d, floating, previewchart, workouteditor, workoutpreview, trainingbrowser) from availableDashboards() — only user-facing dashboards appear in settings - treadmill-pro: full redesign matching QZ app screenshot layout: current segment name (large teal), stats row (dist/time/avgspeed), progress bar, sparkline + lap stats (pace/HR/cadence), interactive speed ± and incline ± control rows, Next Lap / Pause action buttons Responsive CSS for landscape orientation via @media query Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
No description provided.